ZK 處理 zul 要求跟 ajax 要求是由不同的兩個 servlet 處理,過程不太相同。
DHtmlLayoutServlet負責處理 zul 要求,你可以打開 developer tool 來觀察 zul 要求的回傳內容:
如果頁面上有用基本元件以外的元件,ZK 會根據頁面用到的 widget 再動態下載對應的 javascript。例如頁面用到 <borderlayout>
, <script>
,因此除了基本的3 個 wpd 外,會額外下載 zul.layout.wpd 跟 zul.utl.wpd。
當你用瀏覽器訪問 zul 頁面後,接下來跟元件互動的過程都只會發出非同步的 ajax 請求,因此你會發現頁面的 URL 並不會改變。
AU 代表 Asynchronous Update,是指 ZK 從瀏覽器發出 AJAX 並局部更新頁面的過程。
我用一個簡單的點擊按鈕觸發傾聽器的動作來說明 au request 的處理流程。
Event
發給事件目標 ZK 元件,本例中是 Button
當事件在瀏覽器被觸發,ZK 元件會發出 AU request,透過開發者工具 (developer tool) 可得知事件的細節。你可按 F12 在 Chrome 或 Firefox 中都能打開 developer tool。以下是 Chrome的畫面,請觀察 Form Data,其中包含以下欄位:
dtid
, Desktop idcmd
, 事件名稱, 例如 onClick
uuid
, 發生該事件的 DOM element iddata
, 事件相關資料,每個事件會帶不同的資料因為有時候會有多個事件累積起來一次發送,因此 cmd 等 key 會後綴編號,代表事件的順序,如 cmd_0
, cmd_1
,其對應的資料也會有同樣的編號如 uuid_0
, data_0
。
當事件傾聽器執行完後,就會回傳給 client engine 的命令,你可打開 developer tool 來觀察回應內容:
從 AU response 內容就可以回推我們在傾聽器中呼叫了哪些元件上的 method,因此這些資訊也可以用來除錯。這裡我們不用細究每個命令後面帶的一大堆參數,只要能看出幾個關鍵字即可得知大概,下面介紹一些常見的。
呼叫任何 setter method 都會產生 setAttr
這個命令(代表 setAttribute ),例如下面就是呼叫 setVisible(false)
{"rs":[["setAttr",[{$u:'cMIYd'},"visible",false]]],"rid":1}
{"rs":[["addChd",["iB0Zk0",[
['zul.sel.Treeitem','iB0Zy1',{open:false,_loaded:true},{},[
['zul.sel.Treerow','iB0Zz1',{},{},[
['zul.sel.Treecell','iB0Z_2',{label:'< 2.0L(inc.)’},{},[]],
['zul.sel.Treecell','iB0Z02',{label:'3'},{},[]]]]]]],…,"rid":7}
{"rs":[["rm",["zY5Q10"]],["rm",["zY5Qz"]],["rm",["zY5Q60"]],["rm",["zY5Q80"]],["rm",["zY5Qa0"]],["rm"
重繪元件會造成只存在於 client 端的狀態會被伺服器端的狀態覆寫,例如我展開一個 groupbox,但這個開啟狀態如果沒有註冊 onOpen 傾聽器是不會送到伺服器端,因此如果有任何原因促使重繪 groupbox 的話,就會造成 groupbox 變成關閉。
{"rs":[["outer",[{$u:'yZ6Q2'},[
['zul.tab.Tabbox','yZ6Q2',{width:'20%',prolog:'\n\t'},{},[
['zul.tab.Tabs','yZ6Q3',{},{},[
['zul.tab.Tab','yZ6Q8',{$onSelect:false,$onClose:true,label:'tab 1’,iconSclass:'z-icon-book',selected:true},{},[]],
['zul.tab.Tab','yZ6Qf',{$onSelect:false,$onClose:true,label:'tab 2’,iconSclass:'z-icon-book'},{},[]]]],
…],"rid":1}